#pragma once
#include"ref_count.h"
template <typename T>
class weak_ptr;

template<typename T>
class shared_ptr {
private:
	shared_ptr(T* Ptr, Ref_Count* Ref_count):_Ptr(Ptr),_Ref_count(Ref_count) {
		if(_Ref_count)
			_Ref_count->incref();
	}
public:
	shared_ptr()noexcept{}
	shared_ptr(T* Ptr) :_Ptr(Ptr), _Ref_count(new Ref_count_resource<T>(Ptr)) {}
	shared_ptr(const shared_ptr& other) :_Ptr(other._Ptr), _Ref_count(other._Ref_count) {
		if(_Ref_count)
			_Ref_count->incref();
	}
	shared_ptr(shared_ptr&& right){
		swap(_Ptr, right._Ptr);
		swap(_Ref_count, right._Ref_count);
	}
	~shared_ptr() { 
		if(_Ref_count)
			_Ref_count->decref();
	}

	shared_ptr& operator=(const shared_ptr& other) {
		if (&other ==this) return *this;
		if (_Ref_count) _Ref_count->decref();
		_Ref_count = other._Ref_count;
		_Ptr = other._Ptr;
		if(_Ref_count) _Ref_count->incref();
		return *this;
	}
	shared_ptr& operator=(shared_ptr&& right) {
		if (&right == this) return *this;
		if(_Ref_count) _Ref_count->decref();
		_Ref_count = nullptr;
		_Ptr = nullptr;
		swap(_Ref_count, right._Ref_count);
		swap(_Ptr, right._Ptr);
	}

	int use_count() {
		if (_Ref_count) return _Ref_count->use_count();
		return 0;
	}

	bool unique() {
		return !_Ref_count || _Ref_count->use_count() == 1;
	}

	T& operator*() {
		return *_Ptr;
	}
	T* operator->() {
		return _Ptr;
	}

	T* get() {
		return _Ptr;
	}

private:

	T* _Ptr{nullptr};
	Ref_Count* _Ref_count{nullptr};

	friend weak_ptr<T>;
};

